package com.spukmk3me.scenepack.pack0;

import java.util.Hashtable;

/* $if SPUKMK3ME_DEBUG$ */
import com.spukmk3me.debug.Logger;
/* $endif$ */

import com.spukmk3me.scene.Node;
import com.spukmk3me.scene.Scene;
import com.spukmk3me.util.DoublyLinkedList;
import com.spukmk3me.util.Util;

public final class DefaultScene extends Scene
{
    public DefaultScene()
    {
        super( true ); // Use default rendering process
        m_managedNodes      = new Hashtable<String, DefaultNode>();
        m_rootNode          = createNode( ROOT );
    }

    @Override
    public DefaultNode createNode()
    {
        return createNode( null );
    }

    @Override
    public DefaultNode createNode( String name )
    {
        if ( name != null )
        {
            if ( !Util.isLegalName( name ) )
            {
                /* $if SPUKMK3ME_DEBUG$ */
                Logger.trace( "The name: \"" + name + "\" is illegal." );
                /* $endif$ */
                return null;
            }
            
            if ( m_managedNodes.containsKey( name ) )
            {
                /* $if SPUKMK3ME_DEBUG$ */
                Logger.trace( "Node with the name: \"" + name + "\" already exists." );
                /* $endif$ */
                return null;
            }
        }
        
        DefaultNode node = new DefaultNode( name );
        
        if ( name != null )
            m_managedNodes.put( name, node );

        return node;
    }
    
    @Override
    public DefaultNode getRoot()
    {
        return m_rootNode;
    }
    
    @Override
    public DefaultNode getNode( String name )
    {
        return m_managedNodes.get( name );
    }
    
    @Override
    public void insertNodeAfter( Node node, Node predecessor )
    {
        ((DefaultNode)node).insertAfter( (DefaultNode)predecessor );
    }
    
    @Override
    public void attachNode( Node parent, Node child )
    {
        ((DefaultNode)parent).addChild( (DefaultNode)child );
    }
    
    @Override
    public void detachNode( Node node )
    {
        ((DefaultNode)node).detach();
    }
    
    @Override
    public Node detachNode( String name )
    {
        DefaultNode node = getNode( name );
        
        if ( node == null )
            return null;
        
        detachNode( node );
        return node;
    }
    
    @Override
    public void dropNode( Node node )
    {
        if ( node == null )
            throw new NullPointerException();
        
        DoublyLinkedList dropNodeList = new DoublyLinkedList();
        DoublyLinkedList.Iterator itr, etr;
        DefaultNode temp;
        int firstIndex = 0, nParseThisTurn;
        
        dropNodeList.push_back( node );
        
        while ( firstIndex != dropNodeList.length() )
        {
            itr = dropNodeList.first();
            
            for ( int i = firstIndex; i != 0; --i )
                itr.fwrd();
            
            nParseThisTurn = dropNodeList.length() - firstIndex;
            firstIndex  = dropNodeList.length();
            
            for ( int i = nParseThisTurn; i != 0; --i )
            {
                temp = (DefaultNode)itr.data();
                
                if ( temp.c_children != null )
                {
                    DefaultNode child = temp.c_children.c_next;
                    
                    while ( child != temp.c_children )
                    {
                        dropNodeList.push_back( child );
                        child = child.c_next;
                    }
                }
                
                itr.fwrd();
            }
        }
        
        itr = dropNodeList.last();
        etr = dropNodeList.end();
        
        //System.out.println( "Going to drop " + dropNodeList.length() + "nodes" );
        
        for ( ; !itr.equals( etr ); itr.back() )
        {
            temp = (DefaultNode)itr.data();
            temp.detach();
            temp.setEntity( null );
            temp.removeAllAnimators();
            
            if ( temp.getName() != null )
                m_managedNodes.remove( temp.getName() );
        }
    }
    
    @Override
    public Node dropNode( String name )
    {
        DefaultNode node = getNode( name );
        
        if ( node == null )
            return null;

        dropNode( node );
        return node;
    }
    
    @Override
    public void dropChildren( Node node )
    {
        DefaultNode dNode = (DefaultNode)node;
        
        if ( dNode.c_children == null )
            return;
        
        DefaultNode itr = dNode.c_children.c_next;
        
        while ( dNode.c_children != null )
        {
            itr = itr.c_next;
            dropNode( itr.c_prev );
        }
    }
    
    @Override
    public Node dropChildren( String name )
    {
        Node node = getNode( name );
        
        if ( node == null )
            return null;

        dropChildren( node );
        return node;
    }
    
    private DefaultNode m_rootNode;
    private Hashtable<String, DefaultNode> m_managedNodes;
}
